package com.bungarus.om.model;

import com.bungarus.offline.OfflineMessage;
import com.bungarus.offline.OfflineMessagePersist;
import com.bungarus.offline.OfflinePointer;
import org.apache.log4j.Logger;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class OfflineMessageOps {
    Logger logger = Logger.getLogger(OfflineMessagePersist.class);

    private final static OfflineMessageOps ops = new OfflineMessageOps();
    private static MongoTemplate offlineStore;

    public static OfflineMessageOps getInstance(MongoTemplate template) {
        OfflineMessageOps.offlineStore = template;
        return ops;
    }

    public long getOfflinePointerOffset(int tenantId, String uid, String dev){
        OfflinePointer pointer;
        Query query = new Query();
        query.addCriteria(Criteria.where("tenant_id").is(String.valueOf(tenantId)));
        query.addCriteria(Criteria.where("uid").is(uid));
        if(!dev.isEmpty()) {
            query.addCriteria(Criteria.where("dev").is(dev));
        }

        pointer = offlineStore.findOne(query, OfflinePointer.class, OfflinePointer.class.getSimpleName().toLowerCase());
        long pointerOffset = -1;
        if(null != pointer){
            pointerOffset = pointer.getPointer();
        }
        return pointerOffset;
    }

    /**
     * retrieve offline messsages
     * @return List
     */
    public List<OfflineMessage> retrieveByUser(int tenantId, String uid, String app, String dev, int offset, int size){
        List<OfflineMessage> messages = new CopyOnWriteArrayList<>();
        long offlinePointerOffset = this.getOfflinePointerOffset(tenantId, uid, dev);

        if(offlinePointerOffset > -1){
            Query query = new Query();
            query.addCriteria(Criteria.where("message.tenantID").is(tenantId));
            query.addCriteria(Criteria.where("to").is(uid));
            query.addCriteria(Criteria.where("message.app").is(app));
            if(!dev.isEmpty()) {
                query.addCriteria(Criteria.where("message.dev").is(dev));
            }
            query.addCriteria(Criteria.where("offlineId").gt(offlinePointerOffset));
            query.with(new Sort(Sort.Direction.ASC,"offlineId"));
            query.skip(offset).limit(size);

            messages = offlineStore.find(query, OfflineMessage.class, OfflineMessage.class.getSimpleName().toLowerCase());
            return messages;
        }

        return messages;
    }

    /**
     * update offline pointer
     * @param tenantId
     * @param uid user id
     * @param pointer  new pointer
     */
    public void updatePointerByUser(int tenantId, String uid, String app, String dev, long pointer) {
        Query query = new Query();
        query.addCriteria(Criteria.where("tenant_id").is(String.valueOf(tenantId)));
        query.addCriteria(Criteria.where("uid").is(uid));
        query.addCriteria(Criteria.where("app").is(app));
        if(!dev.isEmpty()) {
            query.addCriteria(Criteria.where("dev").is(dev));
        }

        Update update = new Update();
        update.set("pointer", pointer);
        OfflinePointer pointerNew = offlineStore.findAndModify(query, update,
                FindAndModifyOptions.options().returnNew(true),
                OfflinePointer.class,
                OfflinePointer.class.getSimpleName().toLowerCase());

        if(null == pointerNew){
            logger.warn("pointer not updated");
        }
    }
}
